Procedural

  • The Procedural Paradigm follows the Imperative Paradigm but organizes code into procedures (or functions).

Purely Procedural Languages
  • Today, there is almost nothing “purely procedural.”

  • Fortran :

    • Although it evolved over time and gained modern features, the original Fortran was strictly procedural, focusing on functions that manipulated data.

  • Algol :

    • One of the first languages to adopt a purely procedural style.

Concept of "objects" in the Procedural Paradigm
  • Talking about "procedural implementation for objects"  creates a contradiction , since objects imply an object-oriented paradigm (encapsulation, inheritance, polymorphism, etc.).

  • Procedural programming focuses on organizing code around functions that operate on data.

  • Code is organized into functions (or procedures) and control flow, without object-oriented abstractions like classes or inheritance.

Applying the Procedural Paradigm

In C
  • C was designed to be procedural , meaning it relies on functions and procedures (or subroutines) to manipulate data and control execution flow. C code is organized around functions operating on variables and data structures, with flow controlled by loops ( for , while ), conditionals ( if , else ), and function calls.

  • However, C is not purely procedural  for several reasons:

    • Use of data structures :

      • C allows struct s to group data, resembling encapsulation, often seen in OOP.

    • Macros and preprocessing :

      • The preprocessor ( #define , directives) allows abstraction beyond purely procedural limits.

    • Pointers and memory manipulation :

      • Direct memory manipulation provides abstraction capabilities similar to some OOP patterns.

  • Examples :

    • Procedural :

    #include <stdio.h>
    
    int somar(int a, int b) {
        return a + b;
    }
    
    int main() {
        int x = 5;
        int y = 10;
    
        int resultado = somar(x, y);
        printf("Resultado da soma: %d\n", resultado);
    
        return 0;
    }
    
    • "OOP" :

      #include <stdio.h>
      
      typedef struct {
          char rua[100];
          char cidade[50];
          char estado[50];
      } Endereco;
      
      typedef struct {
          char nome[50];
          int idade;
          Endereco endereco;
      } Pessoa;
      
      void imprimir_endereco(const Endereco *e) {
          printf("Endereço: %s, %s, %s\n", e->rua, e->cidade, e->estado);
      }
      
      void imprimir_pessoa(const Pessoa *p) {
          printf("Nome: %s, Idade: %d\n", p->nome, p->idade);
          imprimir_endereco(&p->endereco);
      }
      
      int main() {
          Pessoa p = {"João", 30, {"Rua das Flores", "São Paulo", "SP"}};
          imprimir_pessoa(&p);
      
          return 0;
      }
      
      #include <stdio.h>
      
      typedef struct {
          char nome[50];
          int idade;
      } Pessoa;
      
      void saudar(Pessoa *p) {
          printf("Olá, meu nome é %s e tenho %d anos.\n", p->nome, p->idade);
      }
      
      typedef struct {
          Pessoa pessoa;
          char matricula[20];
      } Estudante;
      
      void saudar_estudante(Estudante *e) {
          saudar(&e->pessoa);
          printf("Minha matrícula é: %s\n", e->matricula);
      }
      
      int main() {
          Estudante e = {{"João", 20}, "12345"};
          saudar_estudante(&e);
          
          return 0;
      }
      
In Rust
  • Rust is a hybrid language .

  • It allows procedural code (functions, data manipulation) but also supports structs and traits, enabling OOP-like abstraction without classical inheritance or polymorphism.

  • Creating "objects" in Rust ( struct  + impl ) is hybrid: procedural logic with object-like composition.

  • Objects in Rust :

    • Structs with methods are not true OOP objects; they use data and function composition .

  • Examples :

    • Hybrid: Procedural + "OOP" :

    struct Carro {
        modelo: String,
        ano: i32,
    }
    
    impl Carro {
        fn novo(modelo: &str, ano: i32) -> Carro {
            Carro {
                modelo: modelo.to_string(),
                ano,
            }
        }
    
        fn detalhes(&self) {
            println!("Modelo: {}, Ano: {}", self.modelo, self.ano);
        }
    }
    
    fn main() {
        let carro1 = Carro::novo("Fusca", 1985);
        carro1.detalhes();
    }
    
    • Procedural :

      fn maior(a: i32, b: i32) -> i32 {
          if a > b { a } else { b }
      }
      
      fn main() {
          let resultado = maior(10, 20);
          println!("O maior número é: {}", resultado);
      }
      
      struct Ponto { x: i32, y: i32 }
      
      fn distancia(p1: &Ponto, p2: &Ponto) -> f64 {
          let dx = p2.x - p1.x;
          let dy = p2.y - p1.y;
          ((dx * dx + dy * dy) as f64).sqrt()
      }
      
      fn main() {
          let p1 = Ponto { x: 3, y: 4 };
          let p2 = Ponto { x: 7, y: 1 };
          println!("Distância: {}", distancia(&p1, &p2));
      }
      
In Zig
  • Zig is fundamentally procedural .

  • It lacks native OOP features like classes, inheritance, or polymorphism.

  • Structs :

    • No inheritance. Uses composition instead.

    • No constructors/destructors; manual init functions handle resource setup.

      const std = @import("std");
      
      const Pessoa = struct {
          nome: []const u8,
          idade: u32,
      
          pub fn init(nome: []const u8, idade: u32) Pessoa {
              return Pessoa{ .nome = nome, .idade = idade };
          },
      
          pub fn saudar(self: *Pessoa) void {
              std.debug.print("Olá, meu nome é {} e tenho {} anos.\n", .{ self.nome, self.idade });
          },
      };
      
      pub fn main() void {
          var pessoa = Pessoa.init("João", 30);
          pessoa.saudar();
      }
      
  • Examples :

    • Procedural :

      const std = @import("std");
      
      fn somar(a: i32, b: i32) i32 {
          return a + b;
      }
      
      pub fn main() void {
          const resultado = somar(10, 20);
          std.debug.print("A soma é: {}\n", .{resultado});
      }
      
    • "OOP" :

      const std = @import("std");
      
      const Falar = struct { falar: fn() void };
      const Cachorro = struct { falar: Falar, nome: []const u8 };
      const Gato = struct { falar: Falar, nome: []const u8 };
      
      fn falar_cachorro() void { std.debug.print("Au Au!\n", .{}); }
      fn falar_gato() void { std.debug.print("Miau!\n", .{}); }
      
      pub fn main() void {
          var cachorro = Cachorro{ .falar = Falar{ .falar = falar_cachorro }, .nome = "Rex" };
          var gato = Gato{ .falar = Falar{ .falar = falar_gato }, .nome = "Whiskers" };
      
          cachorro.falar.falar();
          gato.falar.falar();
      }
      
In Go
  • Go is strongly procedural  with optional abstraction through interfaces.

  • No classes, inheritance, or traditional polymorphism.

  • Examples :

    • Procedural :

      package main
      import "fmt"
      
      func somar(a, b int) int { return a + b }
      
      func main() {
          fmt.Println("Resultado:", somar(10, 20))
      }
      
    • "OOP" :

      package main
      import "fmt"
      
      type Saudável interface { Saudar() }
      
      type Pessoa struct { Nome string; Idade int }
      func (p *Pessoa) Saudar() { fmt.Println("Olá,", p.Nome) }
      
      type Animal struct { Nome string }
      func (a *Animal) Saudar() { fmt.Println("Roar! Eu sou", a.Nome) }
      
      func main() {
          var s Saudável
          pessoa := &Pessoa{"João", 30}
          animal := &Animal{"Leão"}
      
          s = pessoa; s.Saudar()
          s = animal; s.Saudar()
      }
      
In Lua
  • Lua can be used procedurally but can simulate OOP via tables + metatables .

  • Examples :

    • Procedural :

      function somar(a, b) return a + b end
      print("Resultado: " .. somar(5, 10))
      
    • "Simulated OOP" :

      Pessoa = {}; Pessoa.__index = Pessoa
      function Pessoa:new(nome, idade)
          local self = setmetatable({}, Pessoa)
          self.nome, self.idade = nome, idade
          return self
      end
      function Pessoa:saudar()
          print("Olá, meu nome é " .. self.nome .. " e tenho " .. self.idade .. " anos.")
      end
      
      Aluno = setmetatable({}, Pessoa)
      Aluno.__index = Aluno
      function Aluno:new(nome, idade, matricula)
          local self = setmetatable(Pessoa:new(nome, idade), Aluno)
          self.matricula = matricula
          return self
      end
      function Aluno:saudar()
          print("Sou aluno " .. self.nome .. " e minha matrícula é " .. self.matricula)
      end
      
      local pessoa1 = Pessoa:new("João", 30)
      local aluno1 = Aluno:new("Maria", 20, "12345")
      pessoa1:saudar()
      aluno1:saudar()